class Suffix

  # Implements the suffix array, which is used for finding partial matches.

  include Comparable

  @@match_length = nil

  attr_reader :offset, :document

  def initialize(offset, document)
    @offset, @document = offset, document
  end

  def Suffix.set_match_length_for_tests(match_length)
    # To Do: This is hacky and error prone. Find a better way. AW 4/9/2008
    @@match_length = match_length
  end
  
  def Suffix.match_length=(match_length)
    if !@@match_length.nil?
      raise RuntimeError, "Cannot reassign match_length"
    end
    
    @@match_length = match_length
  end

  def Suffix.match_length()
    @@match_length
  end

  def length
    @document.length - @offset
  end
  
  def to_s
    if @@match_length.nil?
      @document.words(@offset).join(" ")
    else
      @document.words(@offset)[0...@@match_length].join(" ")
    end
  end

  def hash
    # To Do: 2. Remove duplicated loop between this code and <=>
    # To Do: 3. Remove the "% 2^32" if possible. It may not be necessary.
    comparison_length = length

    if !@@match_length.nil? and @@match_length < comparison_length
      comparison_length = @@match_length
    end

    result = 17
    
    (0...comparison_length).each { |i| 
      result = 31 * result + self[i].hash()
    }
   
    return result
  end

  def <=>(other)
    shorter_length = length < other.length ? length : other.length

    if !@@match_length.nil? and @@match_length < shorter_length
      shorter_length = @@match_length
    end

    for i in 0...shorter_length
      comp = self[i] <=> other[i]

      return comp if comp != 0
    end

    return 0 if shorter_length == @@match_length

    return length - other.length
  end

  def ==(other)
    (self <=> other) == 0
  end

  def eql?(other)
    (self <=> other) == 0
  end

  def [](index)
    @document[@offset + index]
  end

  # Return true iff this suffix array matches other from
  # their beginnings through the minimum_matches'th elements.
  def matches?(other, minimum_matches)
    return false if length < minimum_matches || other.length < minimum_matches

    for i in 0...minimum_matches
      return false if words[i] != other.words[i]
    end

    return true
  end

  protected
    def words
      @document.words(@offset)
    end

    def same_length?(other)
      words.size == other.words.size
    end
end
